:- module(asset_access, [
        asset_name/3,
        asset_author/3,
        asset_maintained_by/3,
        asset_homepage/3,
        asset_download_page/3,
        asset_contact/3,
        asset_license/3,
        asset_license_URL/3,
        asset_version/3,
        asset_references/3,
        asset_additional_constraints/3,
        asset_additional_freedom/3,
        asset_description/3,
        asset_creation_date/3,
        asset_submitted_by/3,
        asset_submission_date/3,
        asset_environment/3,
        asset_cost/3,
        asset_security_classification/3,
        asset_certification/3,
        asset_package_signature/3,
        asset_check/2,
        asset_update/3,
%% Types
        asset/1,
        asset_field/1
        ], [assertions,basicmodes,regtypes,hiord]).

:- comment(title, "Creating and Consulting Assets").
:- comment(subtitle, "AMOS Project").


:- comment(author, "Manuel Carro and the CLIP Group").
:- comment(author, "Facultad de Inform@'{a}tica").
:- comment(author, "Universidad Polit@'{e}cnica de Madrid").
:- comment(author, "@tt{clip@@dia.fi.upm.es}").
:- comment(author, "@tt{http://www.clip.dia.fi.upm.es/}").


:- comment(module,

"Assets are the basic abstraction resources (e.g., packages,
documentation, etc.) are built on.  An asset contains information
pertaining all the relevant information of a resource, but the
dependencies themselves.  This is so because there might be resources
which do not have explicit dependencies to search for (e.g., pieces of
work which are not ultimately intended to be compiled, such as
licenses).  In order to cater for the existence of these entities, the
@em{asset} abstraction reflects interesting characteristics of such
non-software (but anyway interesting and needed) packages.

The operations herein included are aimed at creating and consulting
instances of the @em{asset} class.  They may change (for example, to
include more operations) should the ontology evolve in that direction.

@include{three_argument_explanation.lpdoc}

@sp

@include{../Doc/acknowledgements.lpdoc}

@newpage

").

:- include(db('argnamesv/argnamesv')).   % Kludge to use local version

:- use_module(library(sort)).
:- use_module(db(user_access)).
:- use_module(db(basic_types)).
:- use_module(db(general_check)).

:- argnames is_an_asset(
        name,
        author,
        maintainer,
        homepage,
        downloadpage,
        contact,
        license,
        licenseurl,
        version,
        references,
        constraints,
        freedom,
        assetdescription,
        creationdate,
        submittedby,
        submissiondate,
        environment,
        cost,
        security,
        certification,
        signature).


fields_and_types([
        field(name,             (nonnull, atom)),
        field(author,           (nonnull, nonemptylist, list(user))),
        field(maintainer,       (null ; list(user))),
        field(homepage,         (null ; atom)),
        field(downloadpage,     (nonnull, atom)),
        field(contact,          (null ; atom)),  % this is the contact e-mail
        field(license,          (nonnull, atom)),
        field(licenseurl,       (null ; atom)),
        field(version,          (nonnull, atom)),
        field(references,       (null ; atom)),
        field(constraints,      (null ; atom)),
        field(freedom,          (null ; atom)),
        field(assetdescription, (nonnull, nonemptylist, list(atom))),
        field(creationdate,     (null ; date)),
        field(submittedby,      (nonnull, user)),
        field(submissiondate,   (nonnull, date)),
        field(environment,      (null ; atom)),
        field(cost,             (null ; atom)),
        field(security,         (null ; atom)),
        field(certification,    (null ; certification)),
        field(signature,        (null ; atom))
       ]).


:- regtype asset(?Asset) # "@var{Asset} is an asset.".

asset(is_an_asset${}).


:- regtype asset_field(?Field)

 # "@var{Field} is one of the field names of an asset".

asset_field(Field):-
        member(Field, is_an_asset$argnames).



:- pred asset_name(Asset, Name, NewAsset):
        asset * string * asset

#"@var{Name} is the name (identifier) of @var{NewAsset}.  It should be
unique within the system, and its presence is required.".

asset_name(Asset, Name, NewAsset):-
        asset_update(Asset, [name-Name], NewAsset).


:- pred asset_author(Asset, Authors, NewAsset):
        asset * list(user) * asset

#"@var{Authors} is the list of authors of @var{NewAsset}.  Its
presence is required, an there must be at least one author.".

asset_author(Asset, Author, NewAsset):-
        asset_update(Asset, [author-Author], NewAsset).


:- pred asset_maintained_by(Asset, Maintainers, NewAsset):
        asset * list(user) * asset

#"@var{Maintainers} is the list of (current) maintainers of
@var{NewAsset}. It may be empty.".

asset_maintained_by(Asset, Maintainer, NewAsset):-
        asset_update(Asset, [maintainer-Maintainer], NewAsset).


:- pred asset_homepage(Asset, Homepage, NewAsset):
        asset * string * asset

#"@var{Homepage} is the identifer of the home page of @var{NewAsset}.".


asset_homepage(Asset, Homepage, NewAsset):-
        asset_update(Asset, [homepage-Homepage], NewAsset).


:- pred asset_download_page(Asset, Download, NewAsset):
        asset * string * asset

#"@var{Download} is an address where @var{NewAsset} can be downloaded
from.".

asset_download_page(Asset, Download, NewAsset):-
        asset_update(Asset, [downloadpage-Download], NewAsset).


:- pred asset_contact(Asset, Contact, NewAsset):
        asset * user * asset

#"@var{Contact} is the name of a contact person for @var{NewAsset}.".

asset_contact(Asset, Contact, NewAsset):-
        asset_update(Asset, [contact-Contact], NewAsset).


:- pred asset_license(Asset, License, NewAsset):
        asset * string * asset

#"@var{License} is the text of the license for @var{NewAsset}.  Its
presence is required.".

asset_license(Asset, License, NewAsset):-
        asset_update(Asset, [license-License], NewAsset).


:- pred asset_license_URL(Asset, URL, NewAsset):
        asset * string * asset

#"@var{URL} is an address where the license of @var{NewAsset} can be
downloaded from.".

asset_license_URL(Asset, URL, NewAsset):-
        asset_update(Asset, [licenseurl-URL], NewAsset).



:- pred asset_version(Asset, Version, NewAsset):
        asset * string * asset

#"@var{Version} is the version of the asset @var{NewAsset}.".

asset_version(Asset, Version, NewAsset):-
        asset_update(Asset, [version-Version], NewAsset).


:- pred asset_references(Asset, References, NewAsset):
        asset * string * asset

#"@var{References} is a set of references concerning @var{NewAsset}.".

asset_references(Asset, References, NewAsset):-
        asset_update(Asset, [references-References], NewAsset).


:- pred asset_additional_constraints(Asset, Constraints, NewAsset):
        asset * string * asset

#"@var{Constraints} is a description of constraints to be taken into
account when using @var{NewAsset}.".

asset_additional_constraints(Asset, Constraints, NewAsset):-
        asset_update(Asset, [constraints-Constraints], NewAsset).


:- pred asset_additional_freedom(Asset, Freedom, NewAsset):
        asset * string * asset

#"@var{Name} is a description of additional properties of the license
of @var{NewAsset}.".

asset_additional_freedom(Asset, Freedom, NewAsset):-
        asset_update(Asset, [freedom-Freedom], NewAsset).



:- pred asset_description(Asset, Description, NewAsset):
        asset * list(string) * asset

#"@var{Description} is a textual description of the asset
@var{NewAsset}. Its presence is required.".

asset_description(Asset, Description, NewAsset):-
        asset_update(Asset, [assetdescription-Description], NewAsset).


:- pred asset_creation_date(Asset, Date, NewAsset):
        asset * date * asset

#"@var{Date} is the date in which @var{NewAsset} was created.".

asset_creation_date(Asset, Date, NewAsset):-
        asset_update(Asset, [creationdate-Date], NewAsset).


:- pred asset_submitted_by(Asset, Submitter, NewAsset):
        asset * user * asset

#"@var{Submitter} is the user which submitted @var{NewAsset}.  Its
presence is required.".

asset_submitted_by(Asset, Submitter, NewAsset):-
        asset_update(Asset, [submittedby-Submitter], NewAsset).


:- pred asset_submission_date(Asset, Date, NewAsset):
        asset * date * asset

#"@var{Date} is the date when @var{NewAsset} was submitted.  Its
presence is required.".

asset_submission_date(Asset, Date, NewAsset):-
        asset_update(Asset, [submissiondate-Date], NewAsset).



:- pred asset_environment(Asset, Environment, NewAsset):
        asset * string * asset

#"@var{Environment} is a textual description of the environment
@var{NewAsset} was designed for or used in.".

asset_environment(Asset, Environment, NewAsset):-
        asset_update(Asset, [target-Environment], NewAsset).


:- pred asset_cost(Asset, Cost, NewAsset):
        asset * string * asset

#"@var{Cost} is the assumed cost of @var{NewAsset}.  It will probably
be not finally used, but it is included for generality: some assets
might require, e.g., an initial cost.".

asset_cost(Asset, Cost, NewAsset):-
        asset_update(Asset, [cost-Cost], NewAsset).


:- pred asset_security_classification(Asset, Class, NewAsset):
        asset * string * asset

#"@var{Class} is the security classification of @var{NewAsset}.".

asset_security_classification(Asset, Class, NewAsset):-
        asset_update(Asset, [security-Class], NewAsset).


:- pred asset_certification(Asset, Certification, NewAsset):
        asset * list(certification) * asset

#"@var{Certification} is the list of certifications applicable to
@var{NewAsset}.  It may be empty.".

asset_certification(Asset, Certification, NewAsset):-
        asset_update(Asset, [certification-Certification], NewAsset).


:- pred asset_package_signature(Asset, Signature, NewAsset):
        asset * string * asset

#"@var{Signture} is the signature of the of @var{NewAsset}; it is
included in order to make it possible to check the integrity of the assets.".


asset_package_signature(Asset, Signature, NewAsset):-
        asset_update(Asset, [signature-Signature], NewAsset).


:- pred asset_check(?Asset, ?WrongFields):
        asset * list(asset_fields)

# "The already formed asset @var{Asset} is checked against the
constraints specified in the ontology definition.
@include{check_definition.lpdoc}".


asset_check(Asset, WrongFields):-
        fields_and_types(F),
        check_each_field(F, Asset, WrongFields).

check_each_field([], _Asset, []).
check_each_field([field(F, T)|Fs], Asset, W):-
        Asset = is_an_asset${F => V},
        (
            check_field(T, V) ->
            W = RestW
        ;
            W = [F|RestW]
        ),
        check_each_field(Fs, Asset, RestW).



:- pred asset_update(+Asset, +PairList, ?NewAsset):
        asset * list(pair) * asset

# "This operation updates @var{Asset} to give @var{NewAsset}.
@var{PairList} is a list of pairs (see @pred{pair}): dash-separated
ground terms @tt{Field-Value}, which are meant to express the name of
a field and its updated value.  @tt{Asset update} is a general call
upon which all the rest of the @tt{update} calls rely.".

asset_update(Asset, PairList, NewAsset):-
        NewAsset = is_an_asset${},               % New asset skeleton
        sort(is_an_asset$argnames, AllFields),
        keysort(PairList, SortedPairList),  %% All sorted in same order now
        update(AllFields, SortedPairList, Asset, NewAsset).

update([], _, _, _).
update([Field|Fields], [Field-NewValue|ToUpdate], Asset, NewAsset):-
        !,
        NewAsset = is_an_asset${Field => NewValue},
        update(Fields, ToUpdate, Asset, NewAsset).
update([Field|Fields], ToUpdate, Asset, NewAsset):-
        Asset = is_an_asset${Field => Value},
        NewAsset = is_an_asset${Field => Value},
        update(Fields, ToUpdate, Asset, NewAsset).

:- comment(version_maintenance,on).


:- comment(version(0*1+5,2003/07/04,12:28*20+'CEST'), "Changed
   use_module and include references to use directory aliases.  (Jesus
   Correas Fernandez)").

:- comment(version(0*1+4,2003/02/20,01:30*34+'CET'), "Ast to Asset
(Manuel Carro)").

:- comment(version(0*1+3,2003/02/14,16:25*56+'CET'), "Changed AssetAfter
(Manuel Carro)").

:- comment(version(0*1+2,2003/02/14,13:33*59+'CET'), "Added a general
 asset_update (Manuel Carro)").

:- comment(version(0*1+1,2003/02/14,12:26*36+'CET'), "Added
asset_fields (Manuel Carro)").

:- comment(version(0*1+0,2003/02/13,20:48*26+'CET'), "Initial version,
with all interfaces included.  (Manuel Carro)").

